<template>
  <div class="preview_3d" v-if="hasDimensional">
    <div :id="modelId" class="scene_3d"></div>
    <div class="config" :style="configStyle" @click.stop v-if="!isScreen">
      <div class="left" v-if="!isClose">
        <CaretLeftOutlined @click="onMove(true)" />
      </div>
      <div class="right" v-else>
        <CaretRightOutlined @click="onMove(false)" />
      </div>

      <div v-if="!isClose" class="content">
        <div :style="toolStyle" class="tool">
          <div class="modal_title">
            <span>三维信息</span>
            <Button @click="isConfig = false">配置</Button>
          </div>
          <div class="modal_content">
            <div class="label">名称:</div>
            <div>{{ structureName || '-' }}</div>
            <div class="label">关联设备:</div>
            <ul>
              <li
                v-for="(item, index) in deviceList"
                :key="index"
                class="mb-4 flex w-full items-center justify-between"
              >
                <img class="mr-4 h-6 w-6" :src="item.url" />
                <span class="flex-1">{{ item.label }}</span>
                <span class="mr-4">{{ item.value }}</span>
              </li>
            </ul>
          </div>
        </div>
        <div :style="infoStyle" class="info">
          <div class="modal_title">
            <span>目录</span>
            <Button @click="isConfig = true">返回</Button>
          </div>
          <div class="modal_content">
            <div class="label">测点列表:</div>
            <div
              v-for="item in pointList"
              :key="item.id"
              class="point_item"
              :class="{
                grayscale:
                  configured.findIndex((i) => i.elementId == item.elementId) !=
                  -1,
              }"
            >
              <img
                src="/static/devices/measure-point.png"
                class="h-6 w-6 select-none"
              />
              <Tooltip>
                <template #title>
                  <div class="grid grid-cols-2">
                    <span>测点名称：</span>
                    <span>{{ item.pointName }}</span>
                    <span>设备编号：</span>
                    <span>{{ item.stationId }}</span>
                    <span>序列号：</span>
                    <span>{{ item.deviceCode }}</span>
                    <span>位置：</span>
                    <span>{{ item.location }}</span>
                  </div>
                </template>
                <div class="name">{{ item.pointName }}</div>
              </Tooltip>

              <Button
                class="item_clear"
                type="text"
                @click="onClear(item)"
                :disabled="
                  configured.findIndex((i) => i.elementId == item.elementId) ==
                  -1
                "
                >清除</Button
              >
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="legend">
      <div class="legend_item">
        <img
          src="/static/devices/measure-point.png"
          class="h-6 w-6 select-none"
        />
        <span>测点</span>
      </div>
    </div>
  </div>
  <div class="preview_3d_close" v-else>
    <div class="pic"></div>
    <div class="error_info">{{ errorInfo || '三维场景生成中...' }}</div>
  </div>
  <FormModal :columns="_item"> </FormModal>
</template>

<script setup lang="tsx">
import { computed, nextTick, reactive, ref, toRaw, useId, watch } from 'vue';
import { realDataChart } from '@/utils';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons-vue';
import { useFormModal } from '@boeyo/hooks';
import { useEventSource } from '@boeyo/hooks';
import { router } from '@boeyo/portal';
import { useDicts } from '@boeyo/portal';
import { useUserStore } from '@boeyo/portal';
import { BoFormProps } from '@boeyo/ui';
import { useHead, useScript } from '@unhead/vue';
import { Button, Tooltip, message } from 'ant-design-vue';
import { useRoute } from 'vue-router';
import { eventBus } from '@/utils/eventMitt';
import { bindList, bindPoint, getViewToken, preview, unbindPoint } from './api';

const errorInfo = ref('');
const hasDimensional = ref(false);
const stationId = ref();
const userStore = useUserStore();
const structureName = ref(history.state.structureName);

const isScreen = computed(() => {
  return route.fullPath.includes('screen');
});
let renderChart;
const init = () => {
  const { renderChart: _renderChart } = realDataChart({
    target: document.getElementById('wave_pic'),
    title: false,
    direction: 'vertical',
    channels: toRaw(channels),
  });
  renderChart = _renderChart;
};
const formatData = (cb) => {
  let data = {};
  const checkData = () => {
    let flag = false;
    if (Object.keys(data).length !== 3) return false;
    Object.values(data)
      .map((item) => item[0][0])
      .reduce((prev, cur) => {
        flag = prev === cur;
        return cur;
      });
    return flag;
  };
  const push = (_data) => {
    Object.keys(_data).forEach((_key) => {
      let key;
      switch (_key) {
        case 'Z':
          key = 'EIZ';
          break;
        case 'N':
          key = 'EIN';
          break;
        case 'E':
          key = 'EIE';
          break;
        default:
          break;
      }
      if (_key !== 'X') {
        data[key] = _data[_key];
      }
    });
    if (checkData()) {
      cb(data);
      data = {};
    }
  };
  return push;
};
const delay = ref(0); //延时
const samplingRate = ref(100); //采样率
const intensity = ref(1); //烈度
const push = formatData((data) => {
  console.log(data, 'data');
  nextTick(() => {
    const box = document.getElementById('wave_pic');
    box.style.background = 'transparent';
  });
  const dataSource = {};
  for (const key in data) {
    if (Object.prototype.hasOwnProperty.call(data, key)) {
      const element = data[key];
      delay.value = element.at(-1)[0] - Date.now();
      nextTick(() => {
        const box = document.getElementById('delay');
        if (!box) return;
        box.innerHTML = delay.value + 'ms';
      });
      dataSource[key] = element.reduce((prev, cur) => {
        if (cur[0] % 100 === 0) {
          prev.push(cur);
        }

        return prev;
      }, []);
    }
  }
  renderChart(dataSource);
});

const { connect, disconnect } = useEventSource(
  // http://eap.dev.boeyo.com
  computed(
    () =>
      `/api/edge/sse/300/${Math.random().toString().slice(-6)}/${stationId.value}`,
  ),
  {
    headers: {
      ['Authorization']: `Bearer ${userStore.token}`,
      'Content-Type': 'application/json',
      Accept: '*/*',
    },
    withCredentials: false,
    onMessage(res) {
      const data = JSON.parse(res);
      if (Object.keys(data).includes('X')) {
        intensity.value = data.X;
      }
      push(data);
    },
    onError(error) {
      console.log(error);
      disconnect();
    },
  },
);
const channels = reactive([
  {
    name: 'EIZ',
    des: '竖桥向',
    color: '#F16995',
  },
  {
    name: 'EIN',
    des: '横桥向',
    color: '#77E3F9',
  },
  {
    name: 'EIE',
    des: '纵桥向',
    color: '#DFC428',
  },
]);
enum ImageEnum {
  'seismograph' = 1,
  'power',
  'terminal',
}

const { deviceTypeEnum } = useDicts(['device_type']);
const deviceTypes = ref(undefined);
const deviceList = computed(() => {
  if (deviceTypes.value) {
    return Object.keys(deviceTypes.value).map((key) => {
      return {
        label: deviceTypeEnum.value[key]?.text,
        value: deviceTypes.value[key],
        url: `/static/devices/${ImageEnum[key]}.png`,
      };
    });
  }
  return [];
});
useHead({
  link: [
    {
      href: '/static/bimface/iconfont.css',
      rel: 'stylesheet',
      type: 'text/css',
    },
  ],
});
const route = useRoute();
const data: any = ref(history.state);
eventBus.on('changeStructure', (state: any) => {
  data.value = state;
});
watch(
  () => data.value,
  (val) => {
    nextTick(() => {
      onLoaded(async () => {
        try {
          if (!val.fileId) {
            errorInfo.value = '暂未上传文件!';
            throw new Error('暂未上传文件!');
          }
          const result = await getViewToken({
            fileId: val.fileId,
            isScreen: isScreen.value ? 1 : null,
          });
          if (result.code !== 200) {
            errorInfo.value = result.msg || '-';
            throw new Error(result.msg);
          }
          const viewToken = result.data.viewToken;
          hasDimensional.value = true;
          renderBim(viewToken);
        } catch (error) {
          hasDimensional.value = false;
          return message.info(error);
        }
      });
    });
  },
  { immediate: true, deep: true },
);
const { onLoaded, onError } = useScript(
  'https://static.bimface.com/api/BimfaceSDKLoader/BimfaceSDKLoader@latest-release.js',
);
const pointList = ref([]);
const configured = ref([]);
const pointInfo = computed(() => {
  const item =
    pointList.value.find((i) => i.stationId === stationId.value) || {};
  return item;
});
const { FormModal, open } = useFormModal({
  size: 'small',
});
const selectList = computed(() => {
  return pointList.value.map((i) => {
    console.log(configured.value, i, '1');

    return {
      label: i.pointName,
      value: i.elementId,
      disabled:
        configured.value.findIndex((item) => i.elementId == item.elementId) !==
        -1,
    };
  });
});
const _item = computed<BoFormProps['columns']>(() => [
  {
    title: '选择测点',
    dataIndex: 'elementId',
    valueType: 'select',
    formItemProps: {
      rules: [
        {
          required: true,
          message: `请选择测点`,
          trigger: 'blur',
        },
      ],
    },
    fieldProps: {
      placeholder: `请选择测点`,
      options: selectList.value,
    },
  },
]);
const getInfo = async () => {
  const result = await preview(history.state.structureId);
  deviceTypes.value = result.data.deviceTypes;
  pointList.value = result.data?.pointList.map((i) => {
    return {
      elementId: i.id,
      labelId: i.stationCode,
      ...i,
    };
  });
  const res = await bindList({ structureId: history.state.structureId });
  configured.value = res.data || [];
  configured.value.forEach((item) => {
    addMarker(item);
  });
};
let app;
let viewer3D;
let config;
let markerContainer;
let drawable;
let customItemContainer;
const createCustomItemContainer = () => {
  if (!customItemContainer) {
    // 创建标签容器配置
    const drawableContainerConfig =
      new Glodon.Bimface.Plugins.Drawable.DrawableContainerConfig();
    // 设置容器配置匹配的对象
    drawableContainerConfig.viewer = viewer3D;
    // 创建标签容器
    customItemContainer = new Glodon.Bimface.Plugins.Drawable.DrawableContainer(
      drawableContainerConfig,
    );
  } else {
    disconnect();
    customItemContainer = '';
    createCustomItemContainer();
  }
};

const onClear = async (item) => {
  console.log(item, 'item');

  const res: any = await unbindPoint(item.id);
  if (res.code !== 200) return;
  markerContainer.removeItemById(item.elementId);
  drawable.removeItemById(item.labelId);
  // configured.value
  const index = configured.value.findIndex(
    (i) => i.elementId == item.elementId,
  );
  configured.value.splice(index, 1);
  console.log(viewer3D, '1');

  viewer3D.render();
  if (customItemContainer) {
    disconnect();
    showInfo.value = '';
    customItemContainer.removeItemById('info');
    customItemContainer = '';
  }
};
const renderBim = (viewToken) => {
  if (app) {
    app.destroy();
  }
  //创建BimfaceSDKLoaderConfig
  const loaderConfig = new BimfaceSDKLoaderConfig();

  loaderConfig.viewToken = viewToken;
  //调用BimfaceSDKLoader的load方法加载模型
  BimfaceSDKLoader.load(loaderConfig, successCallback, failureCallback);

  //加载成功回调函数
  function successCallback() {
    //获取DOM元素
    const domShow = document.getElementById(modelId);
    //创建WebApplication3DConfig
    const webAppConfig =
      new Glodon.Bimface.Application.WebApplication3DConfig();
    //设置创建WebApplication3DConfig的dom元素值
    webAppConfig.domElement = domShow;
    if (isScreen.value) {
      webAppConfig.enableViewHouse = false;
    }

    //创建WebApplication3D
    app = new Glodon.Bimface.Application.WebApplication3D(webAppConfig);
    //添加待显示的模型
    app.addView(viewToken);
    //获取viewer3D对象
    viewer3D = app.getViewer();
    viewer3D.setBackgroundColor(new Glodon.Web.Graphics.Color(3, 19, 34, 0));
    viewer3D.addEventListener(
      Glodon.Bimface.Viewer.Viewer3DEvent.MouseClicked,
      (val) => {
        if (customItemContainer) {
          showInfo.value = '';
          customItemContainer.removeItemById('info');
          customItemContainer = '';
          return;
        }
        if (isConfig.value) return;
        const { worldPosition } = val;
        if (!worldPosition) return message.info('超出模型范围!');
        open({
          title: '选择测点',
          modalType: 'add',
          showMessage: false,
          request: async (params: any) => {
            console.log(params, 'params');
            const item = pointList.value.find(
              (i) => i.elementId == params.elementId,
            );
            const currentItem = {
              ...worldPosition,
              ...item,
              structureId: history.state.structureId,
              pointId: item.id,
            };
            const result: any = await bindPoint(currentItem);
            if (result.code !== 200) return;
            addMarker(currentItem);
            configured.value.push(currentItem);
          },
          defaultValue: {},
        });
      },
    );
    // bim渲染完成
    viewer3D.addEventListener(
      Glodon.Bimface.Viewer.Viewer3DEvent.ViewAdded,
      () => {
        if (!isScreen.value) {
          const box = document.querySelector('.bf-toolbar');
          const div = document.createElement('div');
          div.onclick = () => {
            router.back();
          };
          div.classList.add('bf-button');
          div.classList.add('icon-fanhui');
          div.classList.add('iconfont');
          div.title = '返回列表页';
          box.appendChild(div);
        }
        getInfo();
      },
    );
  }

  //加载失败回调函数
  function failureCallback(error) {
    console.log(error);
  }
};

const modelId = useId();

const isConfig = ref(true);
const configStyle = computed(() => {
  return {
    width: isClose.value ? 0 : '15vw',
  };
});

const toolStyle = computed(() => {
  return {
    width: isConfig.value ? '100%' : 0,
  };
});
const infoStyle = computed(() => {
  return {
    width: !isConfig.value ? '100%' : 0,
  };
});
const isClose = ref(route.fullPath.includes('screen'));
const onMove = (val) => {
  isClose.value = val;
};
watch(
  () => isClose.value,
  (val) => {
    nextTick(() => {
      const box: any = document.body;
      box.style.setProperty('--proview-3d-left', val ? '1vw' : '16.5vw');
    });
  },
  { immediate: true },
);

const addMarker = ({ x, y, z, elementId, labelId, pointName, stationId }) => {
  //引线标签
  const drawableConfig =
    new Glodon.Bimface.Plugins.Drawable.DrawableContainerConfig();
  drawableConfig.viewer = viewer3D;
  drawableConfig.maxNum = 99;
  drawable = new Glodon.Bimface.Plugins.Drawable.DrawableContainer(
    drawableConfig,
  );

  // 构造三维标签容器配置markerContainerConfig
  const markerContainerConfig =
    new Glodon.Bimface.Plugins.Marker3D.Marker3DContainerConfig();
  // 设置markerContainerConfig匹配的viewer对象
  markerContainerConfig.viewer = viewer3D;
  // 构造三维标签容器markerContainer
  markerContainer = new Glodon.Bimface.Plugins.Marker3D.Marker3DContainer(
    markerContainerConfig,
  );
  // 构造三维标签配置项
  const markerConfig = new Glodon.Bimface.Plugins.Marker3D.Marker3DConfig();
  // 为标签指定图片路径
  markerConfig.src = '/static/devices/measure-point.png';
  // 构造点位，并指定为标签的插入点
  markerConfig.worldPosition = { x, y, z };
  // 指定标签大小
  markerConfig.size = 40;

  // 构造三维标签
  const marker = new Glodon.Bimface.Plugins.Marker3D.Marker3D(markerConfig);
  marker.id = elementId;
  // 添加标签的点击事件
  marker.onClick(function (e) {
    e.stopPropagation();
    markerContainer.removeItemById(elementId);
  });
  // 将三维标签添加至容器内
  markerContainer.addItem(marker);

  //引线标签
  //引线标签的配置类
  const config = new Glodon.Bimface.Plugins.Drawable.LeadLabelConfig();

  //引线折点的相对位置
  config.offset = { x: 40, y: -90 };
  //引线标签的内容
  config.text = pointName || '-';
  config.style = {
    lineColor: new Glodon.Web.Graphics.Color('#409EFF'),
    backgroundColor: new Glodon.Web.Graphics.Color('#409EFF'),
    fontSize: 14,
    lineWidth: 2,
  };
  //绑定id
  config.id = labelId;
  //引线标签关联的构件
  config.objectId = elementId;
  config.layerId = stationId;
  //引线标签的世界坐标
  config.worldPosition = new Glodon.Web.Geometry.Point3d(x, y, z);
  //引线标签是否可拖拽
  config.draggable = false;
  //引线标签的视图
  config.viewer = viewer3D;
  const label = new Glodon.Bimface.Plugins.Drawable.LeadLabel(config);
  //引线标签的左键点击事件
  label.onClick((item) => {
    addCustomItem(item);
  });

  drawable.addItem(label);
};

const showInfo = ref('');
const addCustomItem = (object) => {
  console.log(object, 'op');

  createCustomItemContainer();
  if (config) {
    customItemContainer.removeItemById('info');
  }
  if (showInfo.value === object.objectId) return (showInfo.value = '');
  stationId.value = object.layerId;
  // 创建CustomItemConfig
  config = new Glodon.Bimface.Plugins.Drawable.CustomItemConfig();
  config.id = 'info';
  const content = document.createElement('div');
  content.innerHTML = `<div class="custom_info">
      <div class="header">
        <div class="top">
          <div class="top_item">
            <span>设备标识</span>
            <span>${stationId.value || '-'}</span>
          </div>
           <div class="top_item">
            <span>采样率</span>
            <span>${samplingRate.value}</span>
          </div>
          <div class="top_item">
            <span>烈度</span>
            <span>${intensity.value || 1}</span>
          </div>
          <div class="top_item">
            <span>数据延迟</span>
            <span id="delay">${delay.value}ms</span>
          </div>
        </div>
      </div>
      <div id="wave_pic"></div>
    </div>
    `;
  config.content = content;
  config.viewer = viewer3D;

  config.worldPosition = object.worldPosition;
  config.offsetX = 63;
  config.offsetY = -78;
  nextTick(() => {
    if (stationId.value != object.layerId) {
      disconnect();
    }

    console.log(pointInfo.value, 'pointInfo');

    init();
    connect();
  });

  // 创建自定义标签对象
  const customItem = new Glodon.Bimface.Plugins.Drawable.CustomItem(config);
  // 将自定义标签添加至标签容器内
  customItemContainer.addItem(customItem);
  showInfo.value = object.objectId;
};
</script>

<style lang="scss" scoped>
.preview_3d_close {
  position: relative;
  pointer-events: all;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    rgba(0, 14, 29, 0.85) 0%,
    rgba(2, 28, 54, 0.85) 100%
  );
  .pic {
    width: 100%;
    height: 100%;
    background: url('/static/bimface/3d.png') no-repeat;
    background-position: center 30%;
    background-size: 50% 50%;
  }
  .error_info {
    position: absolute;
    bottom: 20%;
    left: 50%;
    font-size: 2vw;
    font-weight: 700;
    transform: translateX(-50%);
  }
}
.preview_3d {
  pointer-events: all;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: space-between;
  padding: 1.5vh;
  position: relative;
  font-size: 1.5vh;
  .legend {
    position: absolute;
    top: 140px;
    right: 4px;
    background: rgba(0, 0, 0, 0.5);
    padding: 0.5vh 1vw;
    border-radius: 6px 0 0 0;
    &_item {
      display: flex;
      align-items: center;
      img {
        margin-right: 1vw;
      }
    }
  }
  .scene_3d {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
  }
  .config {
    border-radius: 6px;
    margin-right: 1vw;
    background-color: rgba(0, 0, 0, 0.5);
    position: relative;
    transition: width ease 0.3s;
    .left,
    .right {
      cursor: pointer;
      position: absolute;
      right: 5px;
      font-size: 2vh;
      color: rgba(0, 0, 0, 0.5);
      top: 50%;
      transform: translateY(-50%);
    }
    .right {
      right: -1vw;
    }
    .content {
      height: calc(100% - 20px);
      margin: 10px;
      display: flex;
      justify-content: space-between;
      overflow: hidden;
    }
    .tool,
    .info {
      transition: width ease 0.3s;
      height: 100%;
      overflow: hidden;
      color: #fff;
      .modal_title {
        display: flex;
        white-space: nowrap;
        justify-content: space-between;
        padding-left: 0.5vw;
        span {
          font-size: 18px;
          font-weight: 700;
        }
      }
      .modal_content {
        padding: 1vw 0 0 0.5vw;
        white-space: nowrap;
        .label {
          padding: 0.5vw 0;
          font-weight: 700;
        }
        .point_item {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 1.2vh;
          font-size: 1.2vh;
          .name {
            flex: 1;
            margin-left: 1.2vw;
          }
          .item_clear {
            cursor: pointer;
            &:hover {
              color: #52a7db;
            }
          }
        }
      }
    }
  }
}
:deep(.bf-toolbar) {
  transition: all 0.3s;
  &.bf-tree-toolbar {
    left: var(--proview-3d-left) !important;
    top: 1.5vh !important;
  }
}
:deep(.bf-panel) {
  transition: all 0.3s;
  left: var(--proview-3d-left) !important;
  top: 1.5vh !important;
}
:deep(.bf-drawable-lead-label) {
  width: fit-content !important;
}
</style>

<route lang="json">
{
  "meta": {
    "title": "场景预览",
    "requireAuth": false,
    "hideInTabs": true
  }
}
</route>

<style lang="scss">
.custom_info {
  background: #000b15;
  width: 24vw;
  font-size: 0.9vh;
  background-size: 100% 100%;
  .header {
    .top {
      display: flex;
      padding: 10px 20px;
      background: url('/static/bimface/header_top.png') no-repeat center;
      background-size: 100% 100%;
      &_item {
        flex: 1;
        padding: 0 15px;
        border-right: 1px solid #ccc;
        display: flex;
        justify-content: space-between;
        white-space: nowrap;
        &:last-child {
          border-right: none;
        }
      }
    }
    .bottom {
      display: flex;
      padding: 10px 20%;
      &_item {
        white-space: nowrap;
        flex: 1;
        padding: 0 15px;
        display: flex;
        justify-content: space-between;
      }
    }
  }
  #wave_pic {
    position: relative;
    height: 30vh;
    width: 100%;
    background: url('/static/bimface/empty.png') no-repeat center;
    background-size: 50% 60%;
  }
}
.on_back_list {
  &::before {
    content: '\e739';
  }
}
</style>
